import { T_task } from '@/obj/class';
import { ifs, ts, Tsrv } from '@/services';
import { N_cStph } from './types';

class T_cmd {
  // 主组件箱
  private compBox: ifs.I_compBox;

  // 主组件ID
  private compID: string;

  // 主组件实例
  private self: N_cStph.cStph;

  // 主页轮询时间间隔，上百点位
  public task: T_task = new T_task(7000);

  // 当前轮询是否开启
  public isOpenTask: boolean = false;

  private readCodes: string[] = [];

  // 警报维度查询信息
  private dimensionQueryInfos: N_cStph.I_dimensionQueryData[] = [];

  // 报警信息
  public alarmInfo: N_cStph.alarmInfo[] = [];

  // 读写异常处理
  public handleException = {
    read: {
      hasWritten: false,
      count: 0
    },
    write: {
      count: 0
    }
  };

  // 主组件created里初始化
  public init(self: N_cStph.cStph, compBoxInfo: ifs.I_compBoxInfo) {
    this.self = self;
    this.compBox = compBoxInfo.TcompBox;
    this.compID = compBoxInfo.compID;
    this.initTask();
  }

  // 初始化所有轮询点位
  private initTask() {
    this.readCodes = [];
    this.self.lineConfig.tanks.forEach(tank => {
      Object.keys(tank.params).forEach(key => {
        this.readCodes.push(tank.params[key].code);
      });
    });

    this.self.craneControlConfig.forEach(crane => {
      Object.keys(crane.params).forEach(key => {
        this.readCodes.push(crane.params[key].code);
      });
    });

    this.self.autoButtonPanel.forEach(autoBtn => {
      if (autoBtn.key === 'autoStart') this.readCodes.push(autoBtn.ecCode);
    });

    this.self.lineHeaderInfo.forEach(info => {
      if (
        info.column.key === 'moldRecordInfo' ||
        info.column.key === 'unmoldRecordInfo'
      ) {
        info.cases.forEach(caseItem => {
          this.readCodes.push(caseItem.ecCode);
        });
      }
    });

    // 获取报警电控点
    this.getAlarmEcDetCode();
  }

  // 获取报警电控点
  public getAlarmEcDetCode() {
    this.doLoadData('dimension_query', {
      ec_code: { $nin: ['null'] }
    }).then(([b, res, rows, msg]) => {
      if (!b) {
        this.self.$msg(msg);
      } else {
        if (!Tsrv.noValue(rows)) {
          // Tsrv.myECR.addEcCodeList(rows.map(it => it.ec_code));
          this.dimensionQueryInfos = rows.map(it => {
            this.readCodes.push(it.ec_code);
            return {
              ecCode: it.ec_code,
              alarmClassification: it.alarm_classification,
              id: it.id,
              equipName: it['m2o|equip_id|equip_account|equip_name'],
              equipID: it['equip_id'],
              content: it.content,
              equipFunName: it['m2o|_sys_fun_id|_sys_fun|title']
            };
          });
        }
      }
    });
  }

  public doLoadData(tableName: string, filter = {}) {
    const gpd = new ts.T_getPartDataArg();
    gpd.setFilter(filter);
    gpd.setFunName(tableName);
    gpd.setTableName(tableName);
    gpd.setDbType(Tsrv.globalVar.dbType.MYSQL);
    gpd.setLang(this.self.$i18n.locale);
    gpd.setPage(1, 99999);
    gpd.setRule({} as ifs.I_rule);

    return Tsrv.getData(gpd);
  }

  public getTcmd(): T_cmd {
    return this;
  }

  // 获取任务信息
  public getTaskInfo() {
    this.loadFilterList(['f_status'], 'produc_line_detail_mgmt').then(rows => {
      if (!Tsrv.noValues(rows)) {
        const taksInfo: N_cStph.I_taskInfo = {
          doneCount: rows.filter(row => row.f_status === 6).length,
          workCount: rows.filter(row => row.f_status === 5).length,
          waitCount: rows.filter(row => row.f_status <= 4).length
        };
        this.self.updateTaskInfo(taksInfo);
      }
    });
  }

  public loadFilterList(
    field: string[],
    funName: string,
    filter = {}
  ): Promise<
    Array<{
      [key: string]: any;
    }>
  > {
    const gpfd: ts.T_GPFD = new ts.T_GPFD();
    gpfd
      .setLang(this.self.$i18n.locale || 'en-US')
      .setFunName(funName)
      .setTableName(funName)
      .setDbType(Tsrv.globalVar.dbType.MYSQL);
    gpfd.setFilter(filter).setAgreedFields(...field);

    return new Promise((resolve, reject) => {
      Tsrv.getData<any, ifs.I_GPFD>(gpfd)
        .then(r => {
          const [b, res, rows, msg] = r;
          resolve(rows);
        })
        .catch(err => {
          this.self.$msg(err);
        });
    });
  }

  public writePlcData(
    data: N_cStph.I_writeCodeRes[],
    isRewrite = false
  ): Promise<boolean> {
    return new Promise((resolve, reject) => {
      Tsrv.standardPostReq<N_cStph.I_writeResp, N_cStph.I_writeRes>(
        {
          writeList: data
        },
        Tsrv.url.scadaWrite
      ).then(([res, e]) => {
        if (!res.success) {
          const codes = [];
          for (const item of data) {
            codes.push(item.ecDetCode);
          }
          this.self.$msg(res.msg);
          reject(false);
          if (isRewrite) {
            // 写入失败记录失败次数，延迟两秒后重新写入，两次均失败则停止写入
            this.handleException.write.count++;
            if (this.handleException.write.count < 2) {
              // 写入失败延迟两秒后重新写入
              setTimeout(() => {
                this.writePlcData(data, true);
              }, 2000);
            }
          }
        } else {
          // 写入成功
          this.handleException.write.count = 0;
          resolve(true);
        }
      });
    });
  }

  // 读取plc数据
  public readPlcData(
    codes: string[]
  ): Promise<N_cStph.I_readResp['data'] | boolean> {
    return new Promise((resolve, reject) => {
      Tsrv.standardPostReq<N_cStph.I_readResp, any>(
        { ecDetCodes: codes },
        Tsrv.url.scadaRead
      ).then(([readResp, err]) => {
        if (!Tsrv.noValue(err)) {
          this.self.$msg(err);
          reject(false);
        }
        if (!readResp.success) {
          this.self.$msg(readResp.msg);
          reject(false);
        }
        resolve(readResp.data);
      });
    });
  }

  // 修改数据,根据传入filter字段修改
  public modifyData(
    tableName: string,
    filterName: string,
    rows: Array<ifs.I_fv[]>
  ): Promise<boolean> {
    const ctd = new ts.T_ctdArg();
    ctd
      .setTableName(tableName)
      .setDbType(Tsrv.globalVar.dbType.MYSQL)
      .setRule({} as ifs.I_rule);
    const datas = [];
    rows.forEach(row => {
      const fileter = {};
      row.forEach(el => {
        if (el.field === filterName) {
          fileter[filterName] = el.value;
        }
      });
      const ctdUpdData = new ts.T_ctdUpdData();
      ctdUpdData.setFilter(fileter);
      ctdUpdData
        .setDataRule({} as ifs.I_rule)
        .setFileInfo({})
        .setRowData(...row.filter(el => el.field !== filterName));
      datas.push(ctdUpdData);
    });
    ctd.setUpdRecDataMany(...datas);
    return new Promise((resolve, reject) => {
      Tsrv.batRows(ctd).then(([b, res, msg]) => {
        if (!b) {
          this.self.$msg(msg);
          reject(false);
        } else {
          resolve(true);
        }
      });
    });
  }

  private readData = () => {
    this.readPlcData(this.readCodes).then(res => {
      if (typeof res === 'boolean') return;
      this.updateSlotInfo(res);
      this.updateCarInfo(res);
      this.updateAutoStartBtn(res);
      this.updateHeaderInfo(res);
      // 报警
      this.handleAlarmInfo(res);
    });
  };

  // 更新槽位信息
  private updateSlotInfo(data: ifs.I_scadaReadResp['data']) {
    // this.self.lineConfig.tanks.forEach(tank => {
    for (const tank of this.self.lineConfig.tanks) {
      Object.keys(tank.params).forEach(key => {
        if (tank.params[key].conversionRate === 1) {
          tank.params[key].value = data[tank.params[key].code].v;
        } else {
          // tank.params[key].value =
          //   data[tank.params[key].code].v * tank.params[key].conversionRate;
          let value =
            data[tank.params[key].code].v * tank.params[key].conversionRate;
          // 如果value值存在小数部分，则保留两位小数
          if (String(value).includes('.')) {
            if (key === 'liquidLevel' || key === 'ph') {
              value = Math.round(value * 1000) / 1000;
            } else {
              value = Math.round(value * 100) / 100;
            }
          }
          tank.params[key].value = value;
        }
      });

      // 保持错误状态最高优先级
      if (tank.status === 'error') {
        continue;
      }

      // 其次处理关闭状态
      if (
        typeof tank.params.isClose !== 'undefined' &&
        tank.params.isClose.value
      ) {
        tank.status = 'closed';
        continue;
      }

      // 然后处理工作状态
      if (tank.params.hangGroupID.value !== 0 && tank.id < 28) {
        tank.status = 'working';
      }
      // 最后默认除缓存位外空闲状态
      else if (tank.id < 28) {
        tank.status = 'idle';
      }
      if (
        typeof tank.params.isClose !== 'undefined' &&
        tank.id >= 28 &&
        !tank.params.isClose.value
      ) {
        tank.status = 'cache';
      }
    }

    Tsrv.store.commit('UPDATE_SLOT_INFO', this.self.lineConfig.tanks);
  }

  // 更新行车信息
  private updateCarInfo(data: ifs.I_scadaReadResp['data']) {
    this.self.craneControlConfig.forEach(crane => {
      Object.keys(crane.params).forEach(key => {
        crane.params[key].value = data[crane.params[key].code].v;

        switch (key) {
          case 'readStationError':
            crane.promptMessage = data[crane.params[key].code].v
              ? '读工位错'
              : '提示消息';
            break;
          case 'pauseFlag':
            if (data[crane.params[key].code].v) crane.logoInfo = '暂停标志';
            break;
          case 'wait':
            if (data[crane.params[key].code].v) crane.logoInfo = '等待标志';
            break;
          case 'horizontalSlowFlag':
            if (data[crane.params[key].code].v) crane.logoInfo = '水平慢速标志';
            break;
          case 'autoProducingFlag':
            if (data[crane.params[key].code].v) {
              crane.logoInfo = '自动生产标志';
            } else if (
              !data[crane.params['pauseFlag'].code].v &&
              !data[crane.params[key].code].v
            ) {
              crane.logoInfo = '手动生产标志';
            }
            break;
          // case 'groupId':
          //   this.updateWorkpieceInfo(data, crane.params[key].code, crane);
          //   break;
          default:
            break;
        }
      });

      // 先更新行车位置再更新车工件信息
      Object.keys(crane.params).forEach(key => {
        if (key === 'groupId')
          this.updateWorkpieceInfo(data, crane.params[key].code, crane);
      });
    });

    // this.self.$emit('UPDATE_CAR_INFO', this.self.craneControlConfig);

    Tsrv.store.commit('UPDATE_CAR_INFO', this.self.craneControlConfig);
  }

  // 更新工件信息
  private updateWorkpieceInfo(
    data: ifs.I_scadaReadResp['data'],
    code: string,
    craneInfo: N_cStph.craneControlConfig
  ) {
    const params = craneInfo.params;
    if (data[code].v !== 0) {
      // 绘制行车工件
      this.self.lineConfig.cranes.forEach(crane => {
        if (crane.id === craneInfo.id) {
          const tankID = this.self.lineConfig.tanks.find(
            tank => tank.params.hangGroupID === data[params.groupId.code].v
          )?.id;

          const isUp = data[params.up.code].v;
          const isDown = data[params.down.code].v;
          // 工件高度
          const workPieceHeight = isUp
            ? crane.position.y + crane.height + 20
            : crane.position.y + crane.height;
          let targetY = isDown
            ? crane.position.y + crane.height + 20
            : crane.position.y + crane.height;

          let status: N_cStph.WorkpieceConfig['status'] = 'waiting';

          if (!isUp && !isDown) {
            targetY = workPieceHeight;
            status = 'waiting';
          } else {
            status = 'processing';
          }

          crane.load = {
            id: data[params.groupId.code].v,
            name: `工件${crane.id}`,
            width: 55,
            height: 20,
            targetY,
            position: {
              x: crane.position.x + 15,
              y: workPieceHeight
            },
            status,
            currentTankId: tankID
          };
        }
      });
    } else {
      // 清除车上工件
      this.self.lineConfig.cranes.forEach(crane => {
        if (crane.id === craneInfo.id) {
          crane.load = null;
        }
      });
    }
    if (data[params.forward.code].v || data[params.backward.code].v) {
      this.self.platingLine.moveCraneTo(
        craneInfo.id,
        data[params.actualStation.code].v
      );
    }
    // } else {
    //   this.self.lineConfig.cranes.forEach(crane => {
    //     if (crane.id === craneInfo.id) {
    //       crane.status = 'idle';
    //     }
    //   });
    // }

    // 如果行车水平到位，则更新行车至实工位
    if (data[params.horizontalarrowed.code].v) {
      this.self.platingLine.moveCraneTo(
        craneInfo.id,
        data[params.actualStation.code].v
      );
    }
  }

  // 更新自动启动按钮状态
  private updateAutoStartBtn(data: ifs.I_scadaReadResp['data']) {
    this.self.autoButtonPanel.forEach(btn => {
      if (btn.key === 'autoStart') btn.show = data[btn.ecCode].v;
    });
  }

  // 更新头部信息
  private updateHeaderInfo(data: ifs.I_scadaReadResp['data']) {
    this.self.lineHeaderInfo.forEach(info => {
      if (
        info.column.key === 'moldRecordInfo' ||
        info.column.key === 'unmoldRecordInfo'
      ) {
        info.cases.forEach(caseItem => {
          caseItem.value = data[caseItem.ecCode].v;
        });
      }
    });
  }

  // 报警处理
  private handleAlarmInfo(codes: ifs.I_scadaReadResp['data']) {
    for (const [key, value] of Object.entries(codes)) {
      const alarmInfo = this.dimensionQueryInfos.find(
        item => item.ecCode === key
      );
      if (!Tsrv.noValue(alarmInfo)) {
        if (codes[key].v) {
          if (!this.alarmInfo.find(item => item.alarmId === alarmInfo.id)) {
            // 报警开始
            const alarmRowID = Tsrv.getSnowIDFmtStr();
            const dimensionQueryID = alarmInfo.id;
            const content = alarmInfo.content;
            const equipID = alarmInfo.equipID;
            this.alarmInfo.push({
              alarmId: alarmInfo.id,
              content: alarmInfo.alarmClassification,
              alarmRowID,
              equipFunName: alarmInfo.equipFunName,
              alarmCode: alarmInfo.ecCode
            });
            // 写入报警表，需填写维度查询id，挂组id
            // 找到该设备的物理挂组id
            let physicalHGID = 0;

            this.self.lineConfig.tanks.forEach(tank => {
              const slotID = this.getSlotID(alarmInfo.equipName);
              if (slotID === tank.id) {
                physicalHGID = tank.params.hangGroupID.value as number;
                tank.status = 'error';
              }
            });
            if (physicalHGID !== 0) {
              this.loadFilterList(['id'], 'produc_line_detail_mgmt', {
                physical_num: physicalHGID
              }).then(rows => {
                if (rows.length > 0) {
                  const hgID = rows[0].id;
                  this.addAlarmRowData(
                    alarmRowID,
                    hgID,
                    dimensionQueryID,
                    content,
                    equipID
                  );
                }
              });
            } else {
              this.addAlarmRowData(
                alarmRowID,
                '',
                dimensionQueryID,
                content,
                equipID
              );
            }

            this.self.lineHeaderInfo.forEach(item => {
              if (item.column.key === 'alert') {
                item.cases = [];
                item.cases.push(...this.alarmInfo);
              }
            });
          }
        } else {
          // 报警结束
          const index = this.alarmInfo.findIndex(
            item => item.alarmId === alarmInfo.id
          );
          if (index !== -1) {
            this.alarmInfo.splice(index, 1);
            const data = [
              [
                {
                  field: 'alarm_id',
                  value: alarmInfo.id
                } as ifs.I_fv,
                {
                  field: 'release_time',
                  value: Tsrv.utils.toDateString(new Date())
                } as ifs.I_fv
              ]
            ];
            this.modifyData('alarm_query', 'alarm_id', data).then(res => {
              if (res) {
                this.self.lineHeaderInfo.forEach(item => {
                  if (item.column.key === 'alert') {
                    item.cases = [];
                    item.cases.push(...this.alarmInfo);
                  }
                });
              }
            });
          }
        }
      }
    }
  }

  // 新增报警信息,维度查询id，挂组id
  private addAlarmRowData(
    rowID: string,
    hangGroupID,
    dimensionQueryID: string,
    content: string,
    equipID: string
  ) {
    const row = [
      [
        {
          field: 'id',
          value: rowID
        } as ifs.I_fv,
        {
          field: 'hang_group_id',
          value: hangGroupID
        } as ifs.I_fv,
        {
          field: 'alarm_id',
          value: dimensionQueryID
        } as ifs.I_fv,
        {
          field: 'content',
          value: content
        } as ifs.I_fv,
        {
          field: 'equip_id',
          value: equipID
        } as ifs.I_fv
      ]
    ];
    this.addTableData('alarm_query', row).then(success => {
      if (success) {
        // 发送scada标签
        this.sendScadaTag(rowID);
      }
    });
  }

  // scada标签发送
  private sendScadaTag(rowID: string) {
    // 获取eventID scada标签
    const filter = {
      id: {
        $eq: rowID
      }
    };
    this.loadFilterList(['alarm_tag_num'], 'alarm_query', filter).then(rows => {
      if (rows.length > 0) {
        const tagNum = rows[0].alarm_tag_num;
        // 发送scada标签
        this.sendScadaTagByNum(tagNum);
      }
    });
  }

  // 发送scada标签
  private sendScadaTagByNum(tagNum: string) {
    // 发送scada标签
    const formData = new FormData();
    formData.append('dbName', Tsrv.getDBName());
    formData.append('eventID', tagNum);
    Tsrv.standardPostReq<N_cStph.I_standardResp>(
      formData,
      Tsrv.url.scadaEventNotify,
      {
        isExternalReq: true
      }
    ).then(([res, e]) => {
      if (!res.success) {
        this.self.$msg(res.msg);
      }
      // 发送事件至首页
      // this.self.$bus.$emit(this.commonEvent.receiveAlarmInfo, this.alarmInfo);
    });
  }

  // 新增表格数据
  public addTableData(
    tableName: string,
    rows: Array<ifs.I_fv[]>
  ): Promise<boolean> {
    const ctd = new ts.T_ctdArg();
    ctd
      .setTableName(tableName)
      .setDbType(Tsrv.globalVar.dbType.MYSQL)
      .setRule({} as ifs.I_rule);
    const data = [];
    rows.forEach(row => {
      const baseData = new ts.T_baseData();
      baseData
        .setDataRule({} as ifs.I_rule)
        .setFileInfo({})
        .setRowData(...row);
      data.push(baseData);
    });
    ctd.setInsRecDataMany({}, ...data);
    return new Promise((resolve, reject) => {
      Tsrv.batRows(ctd).then(([b, res, msg]) => {
        if (!b) {
          this.self.$msg(msg);
          reject(false);
        } else {
          resolve(true);
        }
      });
    });
  }

  // 匹配槽id
  private getSlotID(slotName: string): number {
    const regex = /\d+/;
    const match = slotName.match(regex);

    if (match) {
      return Number(match[0]);
    }
    return 0;
  }

  // 开始任务
  public startTask() {
    // 将readData方法添加到任务队列中
    this.task.addTask(this.readData);
    // 开始任务
    this.task.startTask();
    this.isOpenTask = true;
  }

  public stopTask() {
    this.task.delTask(this.readData);
    this.task.stopTask();
    this.isOpenTask = false;
  }
}
interface I_cmd extends T_cmd {}
export { I_cmd, T_cmd };
